<template>
  <div style="display: flex; height: 100vh">
    <!-- 控制面板 -->
    <div
      style="
        width: 340px;
        background: #232323;
        color: #fff;
        padding: 20px;
        overflow-y: auto;
      "
    >
      <h2>材质类型对比实验</h2>
      <el-form label-width="78px" style="margin-bottom: 12px">
        <el-form-item label="材质类型">
          <el-select v-model="materialType" @change="updateMaterial">
            <el-option label="Basic (无光照)" value="basic" />
            <el-option label="Standard (物理PBR)" value="standard" />
            <el-option label="Phong (高光)" value="phong" />
            <el-option label="Physical (高级PBR)" value="physical" />
            <el-option label="Toon (卡通)" value="toon" />
          </el-select>
        </el-form-item>
      </el-form>
      <div
        style="
          font-size: 15px;
          color: #eee;
          line-height: 1.9;
          background: #333;
          border-radius: 6px;
          padding: 12px 18px;
        "
      >
        <div v-if="materialType === 'basic'">
          <b>Basic</b>（基础材质）<br />
          只显示颜色/贴图，不受任何光照影响，物体始终均匀显示，适合UI、辅助效果等。<br />
          <i>开启/关闭灯光不会影响外观！</i>
        </div>
        <div v-else-if="materialType === 'standard'">
          <b>Standard</b>（物理材质）<br />
          主流真实感渲染，支持金属感、粗糙度，所有光照、阴影、反射都生效。<br />
          <i>表现真实金属/塑料/皮肤等质感，推荐主力使用！</i>
        </div>
        <div v-else-if="materialType === 'phong'">
          <b>Phong</b>（高光材质）<br />
          经典三维高光反射，适合表现光滑表面、高光点强烈。<br />
          <i>适合珠宝、反光表面等，风格比 standard 更强烈</i>
        </div>
        <div v-else-if="materialType === 'physical'">
          <b>Physical</b>（高级物理材质）<br />
          在 Standard
          基础上支持“清漆、透明、折射”等高级参数，可模拟玻璃、水面等特殊效果。<br />
          <i>可用于写实渲染、透明物体、特殊表面</i>
        </div>
        <div v-else-if="materialType === 'toon'">
          <b>Toon</b>（卡通材质）<br />
          有分段色彩/轮廓，适合漫画、动画、风格化可视化。<br />
          <i>有明显的色块、卡通风格，表现二次元物体</i>
        </div>
      </div>
      <el-divider />
      <el-form label-width="60px">
        <template v-for="item in lights" :key="item.name">
          <el-form-item :label="item.label">
            <el-switch v-model="item.on" @change="syncLights" />
            <span style="margin-left: 10px">强度</span>
            <el-slider
              v-model="item.intensity"
              :min="0"
              :max="item.max"
              :step="0.01"
              style="width: 110px"
              @input="syncLights"
            />
          </el-form-item>
        </template>
      </el-form>
      <div style="color: #999; font-size: 12px; line-height: 1.6">
        可自由切换灯光与材质，感受三维表现差异。
      </div>
    </div>
    <!-- three.js 画布 -->
    <div ref="threeBox" style="flex: 1; background: #222"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RectAreaLightUniformsLib } from "three/examples/jsm/lights/RectAreaLightUniformsLib";

// 材质类型
const materialType = ref("standard");

const lights = ref([
  { name: "ambient", label: "环境光", on: true, intensity: 0.4, max: 2 },
  { name: "dir", label: "平行光", on: true, intensity: 1, max: 2 },
  { name: "point", label: "点光源", on: false, intensity: 1.2, max: 3 },
  { name: "spot", label: "聚光灯", on: false, intensity: 2, max: 4 },
  { name: "hemi", label: "半球光", on: false, intensity: 1, max: 3 },
  { name: "rect", label: "区域光", on: false, intensity: 4, max: 10 },
]);

const threeBox = ref(null);
let renderer, scene, camera, controls, mesh, animateId;
let ambientLight, dirLight, pointLight, spotLight, hemiLight, rectLight;
let dirLightHelper, pointLightHelper, spotLightHelper;

onMounted(() => {
  RectAreaLightUniformsLib.init();
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x232323);

  camera = new THREE.PerspectiveCamera(
    60,
    threeBox.value.clientWidth / threeBox.value.clientHeight,
    0.1,
    100
  );
  camera.position.set(3, 2, 7);

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(threeBox.value.clientWidth, threeBox.value.clientHeight);
  renderer.shadowMap.enabled = true;
  threeBox.value.appendChild(renderer.domElement);

  controls = new OrbitControls(camera, renderer.domElement);

  // 地面
  const ground = new THREE.Mesh(
    new THREE.PlaneGeometry(12, 12),
    new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.7 })
  );
  ground.rotation.x = -Math.PI / 2;
  ground.position.y = -1.2;
  ground.receiveShadow = true;
  scene.add(ground);

  // 球体
  mesh = new THREE.Mesh(
    new THREE.SphereGeometry(1, 48, 48),
    createMaterial(materialType.value)
  );
  mesh.position.y = 1;
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  scene.add(mesh);

  scene.add(new THREE.AxesHelper(2));
  addAllLights();
  animate();
});

onBeforeUnmount(() => {
  cancelAnimationFrame(animateId);
  renderer?.dispose?.();
});

// 创建所有光源和辅助器
function addAllLights() {
  ambientLight = new THREE.AmbientLight(0xffffff, lights.value[0].intensity);
  scene.add(ambientLight);

  dirLight = new THREE.DirectionalLight(0xffffff, lights.value[1].intensity);
  dirLight.position.set(4, 8, 4);
  dirLight.castShadow = true;
  scene.add(dirLight);
  dirLightHelper = new THREE.DirectionalLightHelper(dirLight, 0.4);
  scene.add(dirLightHelper);

  pointLight = new THREE.PointLight(0xff77ee, lights.value[2].intensity, 20);
  pointLight.position.set(-2, 4, 3);
  pointLight.castShadow = true;
  scene.add(pointLight);
  pointLightHelper = new THREE.PointLightHelper(pointLight, 0.2);
  scene.add(pointLightHelper);

  spotLight = new THREE.SpotLight(
    0x00ffcc,
    lights.value[3].intensity,
    30,
    Math.PI / 7,
    0.2,
    1.5
  );
  spotLight.position.set(3, 7, 5);
  spotLight.castShadow = true;
  scene.add(spotLight);
  spotLightHelper = new THREE.SpotLightHelper(spotLight);
  scene.add(spotLightHelper);

  hemiLight = new THREE.HemisphereLight(
    0x87ceeb,
    0x444444,
    lights.value[4].intensity
  );
  hemiLight.position.set(0, 8, 0);
  scene.add(hemiLight);

  rectLight = new THREE.RectAreaLight(
    0xffffff,
    lights.value[5].intensity,
    4,
    2
  );
  rectLight.position.set(0, 5, -4);
  rectLight.lookAt(0, 0, 0);
  scene.add(rectLight);
}

// 材质创建工厂
function createMaterial(type) {
  const color = 0x3399ff;
  switch (type) {
    case "basic":
      return new THREE.MeshBasicMaterial({ color });
    case "standard":
      return new THREE.MeshStandardMaterial({
        color,
        metalness: 0.4,
        roughness: 0.5,
      });
    case "phong":
      return new THREE.MeshPhongMaterial({ color, shininess: 60 });
    case "physical":
      return new THREE.MeshPhysicalMaterial({
        color,
        metalness: 0.6,
        roughness: 0.2,
        clearcoat: 1.0,
        clearcoatRoughness: 0.1,
        transmission: 0.7, // 玻璃感
        thickness: 1.2,
      });
    case "toon":
      // Toon 需要 gradientMap，可以直接省略使用基础色
      return new THREE.MeshToonMaterial({ color });
    default:
      return new THREE.MeshStandardMaterial({ color });
  }
}

// 切换材质类型
function updateMaterial() {
  if (!mesh) return;
  mesh.material.dispose();
  mesh.material = createMaterial(materialType.value);
}

// 灯光同步
function syncLights() {
  ambientLight.intensity = lights.value[0].on ? lights.value[0].intensity : 0;
  dirLight.intensity = lights.value[1].on ? lights.value[1].intensity : 0;
  pointLight.intensity = lights.value[2].on ? lights.value[2].intensity : 0;
  spotLight.intensity = lights.value[3].on ? lights.value[3].intensity : 0;
  hemiLight.intensity = lights.value[4].on ? lights.value[4].intensity : 0;
  rectLight.intensity = lights.value[5].on ? lights.value[5].intensity : 0;
  dirLightHelper.update();
  pointLightHelper.update();
  spotLightHelper.update();
}

function animate() {
  animateId = requestAnimationFrame(animate);
  mesh.rotation.y += 0.003;
  controls.update();
  renderer.render(scene, camera);
}
</script>
